/*
 *  Copyright 2020-2025 the original author or authors.
 *  You cannot use this file unless authorized by the author.
 */

package org.ipig.web.security.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.ipig.commons.annotation.CheckSecurity;
import org.ipig.commons.result.GenericResult;
import org.ipig.constants.ResultStatus;
import org.ipig.web.context.HttpWebContext;
import org.ipig.web.security.AuthManager;
import org.ipig.web.security.PermissionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * GenericSecurityCheck
 *
 * @author <a href="mailto:comchnts@163.com">chinats</a>
 * @version $$Id$$
 * @since 1.0
 */
@Slf4j
@Aspect
//@Component
public class GenericSecurityCheck {
    @Autowired(required = false)
    private AuthManager authMgr;

    @Autowired(required = false)
    private PermissionManager permMgr;

    private String tokenName = AuthManager.DEFAULT_TOKEN_NAME;


    public void setTokenName(String tokenName) {
        if (StringUtils.isNotEmpty(tokenName)) {
            this.tokenName = tokenName;
        }
    }


    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void anyMethod() {
    }


    @Around("anyMethod()")
    public Object execute(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest hsReq = HttpWebContext.getRequest();
        HttpServletResponse hsRes = HttpWebContext.getResponse();
        if (hsRes != null && hsReq != null) {
            MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
            Method method = methodSignature.getMethod();
            Class<? extends Object> clz = pjp.getTarget().getClass();
            StringBuilder sb = new StringBuilder();
            RequestMapping methodRM = (RequestMapping) method.getDeclaredAnnotation(RequestMapping.class);
            RequestMapping classRM = (RequestMapping) clz.getDeclaredAnnotation(RequestMapping.class);
            if (classRM != null) {
                String clsRMurl = classRM.value()[0];
                if (StringUtils.isNotBlank(clsRMurl)) {
                    sb.append(clsRMurl);
                }
            }
            if (methodRM != null) {
                String methodRMuri = methodRM.value()[0];
                if (StringUtils.isNotBlank(methodRMuri)) {
                    sb.append(methodRMuri);
                }
            }
            String token = hsReq.getHeader(this.tokenName);
            CheckSecurity anno = (CheckSecurity) method.getAnnotation(CheckSecurity.class);
            if (anno != null &&
                    anno.checkAuth()) {
                if (this.authMgr == null) {
                    this.log.error("未注入{}类型的bean", AuthManager.class.toString());
                }
                if (this.authMgr != null && !this.authMgr.checkToken(token)) {
                    //String msg = MessageFormat.format("token={0}无效.", token);
                    return new GenericResult(ResultStatus.FAILURE, "token无效");
                }
                if (anno.checkPermission()) {
                    if (this.permMgr == null) {
                        this.log.error("未注入{}类型的bean", PermissionManager.class.toString());
                    }
                    if (this.permMgr != null && !this.permMgr.checkPermission(token, sb.toString())) {
                        return new GenericResult(ResultStatus.FAILURE, "无权访问");
                    }
                }
            }
            hsRes.setHeader(this.tokenName, token);
        }
        return pjp.proceed();
    }
}